<script lang="tsx">
import { computed, defineComponent, onMounted, type PropType, ref, unref, watch } from 'vue'
import type { Recordable } from '../types/form'
import { get, isArray, isFunction, omit, isObject, has, isUndefined } from 'lodash-es'
import { useRuleFormItem } from '../common/useFormItem'
import { ElSelectV2 } from 'element-plus'
import type { OptionsItem } from '../types/formItem'
import { propTypes } from '@/types/propTypes'
type ResOpj = { code: number; data: OptionsItem[] | null }

export default defineComponent({
  name: 'ApiSelectV2',
  props: {
    modelValue: {
      type: [String, Number, Array] as PropType<Recordable>,
    },
    modelName: {
      type: [String, Number, Array] as PropType<Recordable>,
    },
    api: {
      type: Function as PropType<(arg?: Recordable) => Promise<ResOpj>>,
      default: null,
    },
    // api params
    params: {
      type: Object as PropType<Recordable>,
      default: () => ({}),
    },
    // support xxx.xxx.xx
    resultField: propTypes.string.def(''),
    labelField: propTypes.string.def('label'),
    valueField: propTypes.string.def('value'),
    // 数据中那个字段表示禁用
    disabledField: {
      type: String,
      default: 'disabled',
    },
    // 自定义部分选项
    innerOptions: {
      type: Array as PropType<OptionsItem[]>,
      default: () => [],
    },
    /**
     * 禁用的值
     */
    disabledValue: {
      type: Array as PropType<string[] | number[]>,
    },
    numberToString: propTypes.bool,
  },
  emit: ['update:modelValue', 'options-change', 'update:modelName'],

  setup(props, { emit, attrs, slots }) {
    const options = ref<OptionsItem[]>([])
    const loading = ref(true)
    const [state] = useRuleFormItem(props, 'modelValue', 'update:modelValue')
    // const state = ref<any>();
    const getOptions = computed(() => {
      const { labelField, valueField, numberToString } = props
      const optionArr = unref(options).reduce((prev, next: Recordable) => {
        if (next) {
          const value = get(next, valueField)
          prev.push({
            ...omit(next, [labelField, valueField]),
            label: get(next, labelField),
            value: numberToString ? `${value}` : value,
          })
        }
        return prev
      }, [] as OptionsItem[])

      return optionArr
    })
    watch(
      () => props.params,
      () => {
        fetch()
      },
      { deep: true },
    )
    watch(
      () => [state.value, getOptions.value],
      ([v, option]: any) => {
        if (isUndefined(v)) {
          emit('update:modelName', v)
        } else if (isArray(v) && option.length) {
          let name: string[] = []
          if (v.length) {
            v.forEach((ve: Recordable) => {
              let one = option.filter((e: Recordable) => e.value == ve)
              if (one.length) {
                name.push(one[0].label)
              }
            })
          }
          emit('update:modelName', name)
        } else {
          if (option.length) {
            option.forEach((e: Recordable) => {
              if (e.value == v) {
                emit('update:modelName', e.label)
              }
            })
          }
        }
      },
    )
    onMounted(() => {
      fetch()
    })

    async function fetch() {
      const api = props.api
      if (!api || !isFunction(api)) return
      options.value = []
      try {
        loading.value = true
        const res = await api(props.params)
        // console.log("res", res)
        if (isObject(res)) {
          if (has(res, 'code') && res.code != 0) {
            return console.error('数据错误')
          }
          if (isArray(res.data)) {
            options.value = res.data
            if (props.innerOptions?.length) {
            }
            options.value = options.value.map((item: any) => {
              item['disabled'] = false
              if (
                isArray(props.disabledValue) &&
                props.disabledValue.includes(item[props.disabledField] as never)
              ) {
                item.disabled = true
              }
              return item
            })
            emitChange()
            return
          }
          //  a.b.c
          if (props.resultField) {
            options.value = get(res, props.resultField) || []
            if (props.innerOptions?.length) {
              options.value = props.innerOptions.concat(options.value)
            }
            emitChange()
          }
        }
        // 数组数据
        if (isArray(res)) {
          options.value = res
          if (props.innerOptions?.length) {
            options.value = props.innerOptions.concat(options.value)
          }
          options.value = options.value.map((item: any) => {
            item['disabled'] = false
            if (
              isArray(props.disabledValue) &&
              props.disabledValue.includes(item[props.disabledField] as never)
            ) {
              item.disabled = true
            }
            return item
          })
          emitChange()
          return
        }
      } catch (error) {
        console.warn(error)
      } finally {
        loading.value = false
      }
    }
    function emitChange() {
      emit('options-change', unref(getOptions))
    }
    return () => {
      return (
        <div>
          <ElSelectV2
            {...attrs}
            loading={loading.value}
            modelValue={state.value}
            options={getOptions.value}
          >
            {{
              loading: () => <div>数据加载中...</div>,
              ...slots,
            }}
          </ElSelectV2>
        </div>
      )
    }
  },
})
</script>
